/**
 ******************************************************************************
 * @file    zb32l03x_hal_usart.h
 * @author  MCU Application Team
 * @Version V0.0.1
 * @Date    2022/08/30
 * @brief   USART HAL module driver.
 @verbatim
 ******************************************************************************
 **/

#include "zb32l03x_hal.h"

#if defined(HAL_USART_MODULE_ENABLED)
/** @addtogroup USART
  * @brief USART HAL module driver.
  * @{
  */

//=============================================================================
//                         Constant Definition
//=============================================================================
#define DUMMY_DATA                      (0xFFFFUL)
#define USART_PDMA_TIMEOUT              (-1)                    //Wait indefinitely until all data has been received or sent

//=============================================================================
//                          Macro Definition
//=============================================================================

//=============================================================================
//                        Structure Definition
//=============================================================================

//=============================================================================
//                       Global Data Definition
//=============================================================================

//=============================================================================
//                     Private Function Definition
//=============================================================================
/**
  * @brief  Configures the USART peripheral.
  * @param  phusart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval None
  */
static void
_USART_SetConfig(
    USART_HandleTypeDef *phusart)
{
    uint32_t pclk = 0U;
    uint32_t mantissa = 0U;
    uint32_t fraciton = 0U;
    uint32_t tmp = 0U;

    pclk = HAL_RCC_GetPCLKFreq();

    mantissa = pclk / (16U * (phusart->Init.BaudRate));     //(Tx or Rx) Div = Fsclk / (16*BaudRate)

    MODIFY_REG(phusart->Instance->BRR, (USART_BRR_DIV_Mantissa), (uint32_t)(mantissa << USART_BRR_DIV_Mantissa_Pos));

    fraciton = (pclk / phusart->Init.BaudRate);

    (fraciton > (mantissa * 16U))? (fraciton = fraciton - (mantissa * 16U)) : (fraciton = (mantissa * 16U) - fraciton);

    MODIFY_REG(phusart->Instance->BRR, (USART_BRR_DIV_Fraction), (uint32_t)((fraciton << USART_BRR_DIV_Fraction_Pos) & USART_BRR_DIV_Fraction_Msk));

    tmp = (uint32_t)phusart->Init.HwFlowCtl;

    MODIFY_REG(phusart->Instance->CR3,
                ((USART_CR3_CTSE) | (USART_CR3_RTSE)),
                tmp);

    CLEAR_BIT(phusart->Instance->CR1, (USART_CR1_TE | USART_CR1_RE));   //When TE/RE bit enable, can not change CPHA/CPOL/STOP bit data.

    tmp = (uint32_t)(phusart->Init.StopBits | phusart->Init.CLKLastBit | phusart->Init.CLKPhase | phusart->Init.CLKPolarity);

    MODIFY_REG(phusart->Instance->CR2,
                (USART_CR2_STOP | USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_LBCL),
                tmp);

    tmp = (uint32_t)(phusart->Init.Mode | phusart->Init.WordLength | phusart->Init.Parity);

    MODIFY_REG(phusart->Instance->CR1,
                (USART_CR1_RE | USART_CR1_TE | USART_CR1_PS | USART_CR1_PCE | USART_CR1_M),
                tmp);

}


/**
  * @brief  The USART module uses interrupt handling to send data once.
  * @param  phusart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
static HAL_StatusTypeDef
_USART_Transmit_IT(
    USART_HandleTypeDef *phusart)
{
    uint16_t tmp = 0U;

    if( phusart->gState != HAL_USART_STATE_BUSY_TX )
    {
        return HAL_BUSY;
    }

    if( (phusart->Init.WordLength == USART_WORDLENGTH_9B) &&
        (phusart->Init.Parity == USART_PARITY_NONE) )
    {
        tmp = (uint16_t)*((uint16_t *)phusart->pTxBuffPtr);

        phusart->pTxBuffPtr += 2;
    }
    else
    {
        tmp = (uint8_t)*(phusart->pTxBuffPtr);

        phusart->pTxBuffPtr++;
    }

    WRITE_REG_MASK(phusart->Instance->DR, USART_DR_DR_Msk, tmp);

    phusart->TxXferCount--;

    if( phusart->TxXferCount == 0U )
    {
        CLEAR_BIT(phusart->Instance->CR1, (USART_CR1_TXEIE_Msk));
    }

    return HAL_OK;
}


/**
  * @brief  The USART module uses interrupt handling to receive data once.
  * @param  phusart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
static HAL_StatusTypeDef
_USART_Receive_IT(
    USART_HandleTypeDef *phusart)
{
    uint16_t tmp = 0U;

    tmp = READ_REG(phusart->Instance->DR);

    if( phusart->RxState != HAL_USART_STATE_BUSY_RX )
    {
        return HAL_BUSY;
    }

    if( (phusart->Init.WordLength == USART_WORDLENGTH_9B) &&
        (phusart->Init.Parity == USART_PARITY_NONE) )
    {
        *((uint16_t *)(phusart->pRxBuffPtr)) = (tmp & 0x01ffU);

        phusart->pRxBuffPtr += 2;
    }
    else
    {
        *phusart->pRxBuffPtr = (tmp & 0x00ffU);

        phusart->pRxBuffPtr++;
    }

    phusart->RxXferCount--;

    if( phusart->RxXferCount == 0U )
    {
        CLEAR_BIT(phusart->Instance->CR1, (USART_CR1_RXNEIE_Msk | USART_CR1_PEIE_Msk));

        CLEAR_BIT(phusart->Instance->CR3, (USART_CR3_EIE_Msk));

    }

    return HAL_OK;
}

/**
  * @brief    USART work on synchronous mode or Half-Full-Duplex mode. The USART
  *         module uses interrupt handling to send and receive data once.
  * @param  phusart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
static HAL_StatusTypeDef
_USART_TransmitReceive_IT(
    USART_HandleTypeDef *phusart)
{
    uint16_t tmp = 0U;

    if( phusart->gState != HAL_USART_STATE_BUSY_TX_RX )
    {
        return HAL_BUSY;
    }


    if( (phusart->TxXferCount) &&
        (__HAL_USART_GET_FLAG(phusart, USART_FLAG_TXE)) )
    {
        if( (phusart->Init.WordLength == USART_WORDLENGTH_9B) &&
            (phusart->Init.Parity == USART_PARITY_NONE) )
        {
            tmp = (uint16_t)*((uint16_t *)phusart->pTxBuffPtr);

            phusart->pTxBuffPtr += 2;
        }
        else
        {
            tmp = (uint8_t)*(phusart->pTxBuffPtr);

            phusart->pTxBuffPtr++;
        }

        WRITE_REG_MASK(phusart->Instance->DR, USART_DR_DR_Msk, tmp);

        phusart->TxXferCount--;

        if( phusart->TxXferCount == 0U )
        {
            CLEAR_BIT(phusart->Instance->CR1, (USART_CR1_TXEIE_Msk));
        }
    }

    if( (phusart->RxXferCount) &&
        (__HAL_USART_GET_FLAG(phusart, USART_FLAG_RXNE)) )
    {
        tmp = READ_REG(phusart->Instance->DR);

        if( (phusart->Init.WordLength == USART_WORDLENGTH_9B) &&
            (phusart->Init.Parity == USART_PARITY_NONE) )
        {
            *((uint16_t *)(phusart->pRxBuffPtr)) = (tmp & 0x01ffU);

            phusart->pRxBuffPtr += 2;
        }
        else
        {
            *phusart->pRxBuffPtr = (tmp & 0x00ffU);

            phusart->pRxBuffPtr++;
        }

        phusart->RxXferCount--;

        if( phusart->RxXferCount == 0U )
        {
            CLEAR_BIT(phusart->Instance->CR1, (USART_CR1_RXNEIE_Msk | USART_CR1_PEIE));

            CLEAR_BIT(phusart->Instance->CR3, (USART_CR3_EIE_Msk));
        }

    }

    return HAL_OK;
}

/**
  * @brief  Read the value of the SR register to obtain the status of the interrupt bit.
  * @param  phusart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
static HAL_StatusTypeDef
_USART_WaitOnFlagUntilTimeout(
    USART_HandleTypeDef *phusart,
    uint32_t            Flag,
    FlagStatus          Status,
    uint32_t            Tickstart,
    uint32_t            Timeout)
{
    /* Wait until flag is set */
    while ( (__HAL_USART_GET_FLAG(phusart, Flag) ? SET : RESET) == Status )
    {
        /* Check for the Timeout */
        if ( (Timeout != HAL_MAX_DELAY) && ((Timeout == 0U) ||
             ((HAL_GetTick() - Tickstart) > Timeout)) )
        {
            /* Disable the USART TC/TXE/RXNE/PEIE/EIE Interrupt */
            CLEAR_BIT( phusart->Instance->CR1, (USART_CR1_TCIE_Msk | USART_CR1_TXEIE_Msk | USART_CR1_RXNEIE_Msk | USART_CR1_PEIE_Msk) );
            CLEAR_BIT( phusart->Instance->CR3, (USART_CR3_EIE_Msk) );

            phusart->gState = HAL_USART_STATE_READY;
            phusart->RxState = HAL_USART_STATE_READY;

            return HAL_TIMEOUT;
        }
    }

    return HAL_OK;
}

#if defined(HAL_DMA_MODULE_ENABLED)
//USART PDMA Config Function===================================================
/**
  * @brief  Gets the channel that USART uses to transmit data using PDMA.
  * @param  phusart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  Status    USART work state.
  *                     @arg HAL_USART_STATE_BUSY_TX: USART will send data.
  *                     @arg HAL_USART_STATE_BUSY_RX: USART will receive data.
  * @retval HAL DMA Channel
  */
static HAL_DMA_Channel_TypeDef
_USART_GetPDMAChannel(
    USART_HandleTypeDef *pHUsart,
    HAL_USART_StateTypeDef Status)
{
    HAL_DMA_Channel_TypeDef channel_id = HAL_DMA_CHANNEL_00;

    if( pHUsart->Instance == USART2 )
    {
        if( Status == HAL_USART_STATE_BUSY_TX )
        {
            channel_id = HAL_DMA_CHANNEL_USART2_TX;
        }
        else
        {
            channel_id = HAL_DMA_CHANNEL_USART2_RX;
        }
    }
    if( pHUsart->Instance == USART3 )
    {
        if( Status == HAL_USART_STATE_BUSY_TX )
        {
            channel_id = HAL_DMA_CHANNEL_USART3_TX;
        }
        else
        {
            channel_id = HAL_DMA_CHANNEL_USART3_RX;
        }
    }

    return channel_id;
}


/**
  * @brief  Configure the working parameters of the DMA channel when USART sends data.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pData  Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size   Amount of data elements (uint8 or uint16) to be sent.
  * @retval HAL Status
  */
static HAL_StatusTypeDef
_USART_Transmit_PDMA_Config(
    USART_HandleTypeDef *pHUsart,
    uint8_t *pData,
    uint16_t Size)
{
    HAL_DMA_Descriptor_Cfg_TypeDef  hpdma_channel_config    = {0};
    HAL_DMA_Xfer_Cfg_TypeDef        hpdma_tran_data_config  = {0};
    HAL_StatusTypeDef               rval                    = HAL_OK;

    if( (!pHUsart->pHDma) ||
        (!pData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    //Config PDMA work infomation in SRAM.
    hpdma_channel_config.xfer_bytes = Size;
    hpdma_channel_config.type       = DMA_DESCRIPTOR_TYPE_PRIMARY;
    hpdma_channel_config.dst_inc    = DMA_DATA_INC_NONE;
    hpdma_channel_config.arbit_rate = DMA_ARBITRATION_RATE_1;
    hpdma_channel_config.timeout    = USART_PDMA_TIMEOUT;
    hpdma_channel_config.src_addr   = (void *)pData;
    hpdma_channel_config.dst_addr   = (void *)&(pHUsart->Instance->DR);
    if( (pHUsart->Init.Parity == USART_PARITY_NONE) &&
        (pHUsart->Init.WordLength == USART_WORDLENGTH_9B) )
    {
        hpdma_channel_config.src_inc = DMA_DATA_INC_HALFWORD;
        hpdma_channel_config.unit_size = DMA_DATA_SIZE_HALFWORD;
        hpdma_channel_config.xfer_bytes = (Size*2);
    }
    else
    {
        hpdma_channel_config.src_inc = DMA_DATA_INC_BYTE;
        hpdma_channel_config.unit_size = DMA_DATA_SIZE_BYTE;
    }

    rval = HAL_DMA_Set_Descriptor(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_TX), &hpdma_channel_config, NULL);
    if( rval != HAL_OK )
    {
        return rval;
    }

    //Config PDMA ready work.
    hpdma_tran_data_config.is_immediate = RESET;
    hpdma_tran_data_config.mode         = HAL_DMA_MODE_BASIC;
    hpdma_tran_data_config.timeout      = USART_PDMA_TIMEOUT;
    hpdma_tran_data_config.type         = DMA_DESCRIPTOR_TYPE_PRIMARY;
    hpdma_tran_data_config.user_data    = Size;

    rval = HAL_DMA_Channel_Sart(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_TX), &hpdma_tran_data_config);

    return rval;
}


/**
  * @brief  Configure the working parameters of the DMA channel when USART receives data.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pData  Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size   Amount of data elements (uint8 or uint16) to be receive.
  * @retval HAL Status
  */
static HAL_StatusTypeDef
_USART_Receive_PDMA_Config(
    USART_HandleTypeDef *pHUsart,
    uint8_t *pData,
    uint16_t Size)
{
    HAL_DMA_Descriptor_Cfg_TypeDef  hpdma_channel_config    = {0};
    HAL_DMA_Xfer_Cfg_TypeDef        hpdma_tran_data_config  = {0};
    HAL_StatusTypeDef               rval                    = HAL_OK;

    if( (!pHUsart->pHDma) ||
        (!pData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    //Config PDMA work infomation in SRAM.
    hpdma_channel_config.arbit_rate = DMA_ARBITRATION_RATE_1;
    hpdma_channel_config.dst_addr   = (void *)pData;
    hpdma_channel_config.src_addr   = (void *)&(pHUsart->Instance->DR);
    hpdma_channel_config.src_inc    = DMA_DATA_INC_NONE;
    hpdma_channel_config.timeout    = USART_PDMA_TIMEOUT;
    hpdma_channel_config.type       = DMA_DESCRIPTOR_TYPE_PRIMARY;
    hpdma_channel_config.xfer_bytes = Size;
    if( (pHUsart->Init.Parity == USART_PARITY_NONE) &&
        (pHUsart->Init.WordLength == USART_WORDLENGTH_9B) )
    {
        hpdma_channel_config.dst_inc = DMA_DATA_INC_HALFWORD;
        hpdma_channel_config.unit_size = DMA_DATA_SIZE_HALFWORD;
        hpdma_channel_config.xfer_bytes = (Size*2);
    }
    else
    {
        hpdma_channel_config.dst_inc = DMA_DATA_INC_BYTE;
        hpdma_channel_config.unit_size = DMA_DATA_SIZE_BYTE;
    }

    rval = HAL_DMA_Set_Descriptor(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_RX), &hpdma_channel_config, NULL);
    if( rval != HAL_OK )
    {
        return rval;
    }

    //Config PDMA ready work.
    hpdma_tran_data_config.is_immediate = RESET;
    hpdma_tran_data_config.mode         = HAL_DMA_MODE_BASIC;
    hpdma_tran_data_config.timeout      = USART_PDMA_TIMEOUT;
    hpdma_tran_data_config.type         = DMA_DESCRIPTOR_TYPE_PRIMARY;
    hpdma_tran_data_config.user_data    = Size;

    rval = HAL_DMA_Channel_Sart(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_RX), &hpdma_tran_data_config);

    return rval;
}

#endif      //__HAL_DMA_MODULE_ENABLED


//=============================================================================
//                          Public Function
//=============================================================================

/**
  * @brief  Initialize the USART peripheral.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Init(USART_HandleTypeDef *pHUsart)
{
    /* Check handle is valid*/
    if( !pHUsart )
    {
        return HAL_ERROR;
    }

    /* Check whether the input parameters are valid. */
    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_BAUDRATE(pHUsart->Init.BaudRate));
    assert_param(IS_USART_HARDWARE_FLOW_CONTROL(pHUsart->Init.HwFlowCtl));
    assert_param(IS_USART_MODE(pHUsart->Init.Mode));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));
    assert_param(IS_USART_STOPBITS(pHUsart->Init.StopBits));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_CLKPOLARITY(pHUsart->Init.CLKPolarity));
    assert_param(IS_USART_CLKPHASE(pHUsart->Init.CLKPhase));
    assert_param(IS_USART_CLKLASTBIT(pHUsart->Init.CLKLastBit));

    /* Enable module clock signal and configure related IO pins. */
    if( pHUsart->gState == HAL_USART_STATE_RESET )
    {
        pHUsart->Lock = HAL_UNLOCKED;

        HAL_USART_MspInit(pHUsart);
    }

    pHUsart->gState = HAL_USART_STATE_BUSY;

    /* Prevent the module from taking actions that do not meet expectations. */
    __HAL_USART_DISABLE(pHUsart);

    /* Initializes the module register configuration based on the parameters configured in the handle. */
    _USART_SetConfig(pHUsart);

    /* Clears the module enabling bit data that is incompatible with synchronous mode. */
    CLEAR_BIT(pHUsart->Instance->CR2, (USART_CR2_CLKEN | USART_CR2_LINEN));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_HDSEL | USART_CR3_IREN));
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_SYNSPI_Msk);
    SET_BIT(pHUsart->Instance->CR2, USART_CR2_CLKEN_Msk);

    /* The module is ready to work. */
    __HAL_USART_ENABLE(pHUsart);

    /* Initialize the status parameters. */
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;
    pHUsart->RxState = HAL_USART_STATE_READY;
    pHUsart->gState = HAL_USART_STATE_READY;

    return HAL_OK;
}




/**
  * @brief  De-Initialize the USART peripheral.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_DeInit(USART_HandleTypeDef *pHUsart)
{
    /* Check handle is valid*/
    if( !pHUsart )
    {
        return HAL_ERROR;
    }

    /* Check whether the input parameters are valid. */
    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    pHUsart->gState = HAL_USART_STATE_BUSY;
    pHUsart->RxState = HAL_USART_STATE_BUSY;

    /* Disable module. */
    __HAL_USART_DISABLE(pHUsart);

    /* Close the module clock and IO pins. */
    HAL_USART_MspDeInit(pHUsart);

    /* Reset module status parameters. */
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;
    pHUsart->gState = HAL_USART_STATE_RESET;
    pHUsart->RxState = HAL_USART_STATE_RESET;

    pHUsart->Lock = HAL_UNLOCKED;

    return HAL_OK;
}



/**
  * @brief  Initialize the USART peripheral work on asynchronous mode.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Asynchronous_Init(USART_HandleTypeDef *pHUsart)
{
    /* Check handle is valid*/
    if( !pHUsart )
    {
        return HAL_ERROR;
    }

    /* Check whether the input parameters are valid. */
    assert_param(IS_USART_HWELOW_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_BAUDRATE(pHUsart->Init.BaudRate));
    assert_param(IS_USART_HARDWARE_FLOW_CONTROL(pHUsart->Init.HwFlowCtl));
    assert_param(IS_USART_MODE(pHUsart->Init.Mode));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));
    assert_param(IS_USART_STOPBITS(pHUsart->Init.StopBits));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));

    /* Enable module clock signal and configure related IO pins. */
    if( pHUsart->gState == HAL_USART_STATE_RESET )
    {
        pHUsart->Lock = HAL_UNLOCKED;

        HAL_USART_MspInit(pHUsart);
    }

    pHUsart->gState = HAL_USART_STATE_BUSY;

    /* Prevent the module from taking actions that do not meet expectations. */
    __HAL_USART_DISABLE(pHUsart);

    /* Initializes the module register configuration based on the parameters configured in the handle. */
    _USART_SetConfig(pHUsart);

    /* Clears the module enabling bit data that is incompatible with asynchronous mode. */
    CLEAR_BIT(pHUsart->Instance->CR2, (USART_CR2_CLKEN | USART_CR2_LINEN));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_HDSEL | USART_CR3_IREN));

    /* The module is ready to work. */
    __HAL_USART_ENABLE(pHUsart);

    /* Initialize the status parameters. */
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;
    pHUsart->RxState = HAL_USART_STATE_READY;
    pHUsart->gState = HAL_USART_STATE_READY;

    return HAL_OK;
}


/**
  * @brief  Initialize the USART peripheral work on Half-Duplex mode.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_HalfDuplex_Init(USART_HandleTypeDef *pHUsart)
{
    /* Check handle is valid*/
    if( !pHUsart )
    {
        return HAL_ERROR;
    }

    /* Check whether the input parameters are valid. */
    assert_param(IS_USART_HALFDUPLEX_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_BAUDRATE(pHUsart->Init.BaudRate));
    assert_param(IS_USART_MODE(pHUsart->Init.Mode));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));
    assert_param(IS_USART_STOPBITS(pHUsart->Init.StopBits));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));

    /* Enable module clock signal and configure related IO pins. */
    if( pHUsart->gState == HAL_USART_STATE_RESET )
    {
        pHUsart->Lock = HAL_UNLOCKED;

        HAL_USART_MspInit(pHUsart);
    }

    pHUsart->gState = HAL_USART_STATE_BUSY;

    /* Prevent the module from taking actions that do not meet expectations. */
    __HAL_USART_DISABLE(pHUsart);

    /* Initializes the module register configuration based on the parameters configured in the handle. */
    _USART_SetConfig(pHUsart);

    /* In half-duplex mode, USART can only send or receive data at the same time. */
    CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_TE | USART_CR1_RE));
    if(pHUsart->Init.Mode != USART_MODE_TX_RX)
    {
        MODIFY_REG(pHUsart->Instance->CR1, (USART_CR1_TE | USART_CR1_RE) , pHUsart->Init.Mode);
    }

    /* Clears the module enabling bit data that is incompatible with half-duplex mode. */
    CLEAR_BIT(pHUsart->Instance->CR2, (USART_CR2_CLKEN | USART_CR2_LINEN));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_HDSEL | USART_CR3_IREN));
    SET_BIT(pHUsart->Instance->CR3, USART_CR3_HDSEL);

    /* The module is ready to work. */
    __HAL_USART_ENABLE(pHUsart);

    /* Initialize the status parameters. */
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;
    pHUsart->RxState = HAL_USART_STATE_READY;
    pHUsart->gState = HAL_USART_STATE_READY;

    return HAL_OK;
}


/**
  * @brief  Initialize the USART peripheral work on LIN mode.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  BreakDetectLength Specifies the LIN break detection length.
  *         This parameter can be one of the following values:
  *            @arg USART_LINBREAKDETECTLENGTH_10B: 10-bit break detection.
  *            @arg USART_LINBREAKDETECTLENGTH_11B: 11-bit break detection.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_LIN_Init(USART_HandleTypeDef *pHUsart, uint32_t BreakDetectLength)
{
    /* Check handle is valid*/
    if( !pHUsart )
    {
        return HAL_ERROR;
    }

    /* Check whether the input parameters are valid. */
    assert_param(IS_USART_LIN_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_BAUDRATE(pHUsart->Init.BaudRate));
    assert_param(IS_USART_MODE(pHUsart->Init.Mode));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_LIN_BREAKDETECTLENGTH(BreakDetectLength));

    /* Enable module clock signal and configure related IO pins. */
    if( pHUsart->gState == HAL_USART_STATE_RESET )
    {
        pHUsart->Lock = HAL_UNLOCKED;

        HAL_USART_MspInit(pHUsart);
    }

    pHUsart->gState = HAL_USART_STATE_BUSY;

    /* Prevent the module from taking actions that do not meet expectations. */
    __HAL_USART_DISABLE(pHUsart);

    /* Initializes the module register configuration based on the parameters configured in the handle. */
    _USART_SetConfig(pHUsart);

    CLEAR_BIT(pHUsart->Instance->CR2, USART_CR2_STOP);
    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_M);
    MODIFY_REG(pHUsart->Instance->CR2, USART_CR2_LBDL, BreakDetectLength);

    /* Clears the module enabling bit data that is incompatible with LIN mode. */
    CLEAR_BIT(pHUsart->Instance->CR2, (USART_CR2_CLKEN | USART_CR2_LINEN));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_HDSEL | USART_CR3_IREN));
    SET_BIT(pHUsart->Instance->CR2, USART_CR2_LINEN_Msk);

    /* The module is ready to work. */
    __HAL_USART_ENABLE(pHUsart);

    /* Initialize the status parameters. */
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;
    pHUsart->RxState = HAL_USART_STATE_READY;
    pHUsart->gState = HAL_USART_STATE_READY;

    return HAL_OK;
}



/**
  * @brief  Initialize the USART peripheral work on Multi-Processor mode.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  Address The mailing address of this module.This parameter must be less than 16.
  * @param  WakeUpMethod  The way this module wakes up.
  *         This parameter can be one of the following values:
  *             @arg USART_WAKEUPMETHOD_IDLELINE: The module is awakened when the bus is idle.
  *             @arg USART_WAKEUPMETHOD_ADDRESSMARK: The module wakes up when the correct addressing data is received.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_MultiProcessor_Init(USART_HandleTypeDef *pHUsart, uint8_t Address, uint32_t WakeUpMethod)
{
    /* Check handle is valid*/
    if( !pHUsart )
    {
        return HAL_ERROR;
    }

    /* Check whether the input parameters are valid. */
    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_BAUDRATE(pHUsart->Init.BaudRate));
    assert_param(IS_USART_HARDWARE_FLOW_CONTROL(pHUsart->Init.HwFlowCtl));
    assert_param(IS_USART_MODE(pHUsart->Init.Mode));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));
    assert_param(IS_USART_STOPBITS(pHUsart->Init.StopBits));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_WAKEUPMETHOD(WakeUpMethod));

    /* Enable module clock signal and configure related IO pins. */
    if( pHUsart->gState == HAL_USART_STATE_RESET )
    {
        pHUsart->Lock = HAL_UNLOCKED;

        HAL_USART_MspInit(pHUsart);
    }

    pHUsart->gState = HAL_USART_STATE_BUSY;

    /* Prevent the module from taking actions that do not meet expectations. */
    __HAL_USART_DISABLE(pHUsart);

    /* Initializes the module register configuration based on the parameters configured in the handle. */
    _USART_SetConfig(pHUsart);

    /* Initializes the module register configuration based on the parameters configured in the handle. */
    MODIFY_REG(pHUsart->Instance->CR2, USART_CR2_ADD, ((Address << USART_CR2_ADD_Pos) & USART_CR2_ADD_Msk));
    MODIFY_REG(pHUsart->Instance->CR1, USART_CR1_WAKE, (uint32_t)WakeUpMethod);

    /* Clears the module enabling bit data that is incompatible with asynchronous mode. */
    CLEAR_BIT(pHUsart->Instance->CR2, (USART_CR2_CLKEN | USART_CR2_LINEN));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_HDSEL | USART_CR3_IREN));

    /* The module is ready to work. */
    __HAL_USART_ENABLE(pHUsart);

    /* Initialize the status parameters. */
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;
    pHUsart->RxState = HAL_USART_STATE_READY;
    pHUsart->gState = HAL_USART_STATE_READY;

    return HAL_OK;
}



/**
  * @brief  USART MSP Init.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_MspInit(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
             the HAL_USART_MspInit could be implemented in the user file
    */
}

/**
  * @brief  USART MSP DeInit.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_MspDeInit(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
             the HAL_USART_MspDeInit could be implemented in the user file
    */
}


/**
  * @brief  Send an amount of data in blocking mode.
  * @note   When USART parity is not enabled, and word length is configured to 9 bits,
  *         the sent data is handled as a set of uint16. In this case, size must indicate the number
  *         of uint16 provided through pTxData.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pTxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent.
  * @param  Timeout Timeout duration.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Transmit(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint16_t Size, uint32_t Timeout)
{
    HAL_StatusTypeDef rval      = HAL_OK;
    uint32_t tickstart          = 0U;
    uint8_t  *ptr_8bits         = (uint8_t *)pTxData;
    uint16_t *ptr_16bits        = (uint16_t *)pTxData;

    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }

    //Check input parameters valid.
    if( (!pTxData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));


    __HAL_LOCK(pHUsart);

    pHUsart->gState     = HAL_USART_STATE_BUSY_TX;
    pHUsart->ErrorCode  = HAL_USART_ERROR_NONE;

    tickstart               = HAL_GetTick();
    pHUsart->TxXferCount    = Size;
    pHUsart->TxXferSize     = Size;

    _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TXE, RESET, tickstart, Timeout);

    while( pHUsart->TxXferCount )
    {
        pHUsart->TxXferCount--;

        //When word length is 9bits and no parity data, pTxData will be used as an unsigned 16-bit data pointer.
        if( (pHUsart->Init.WordLength == USART_WORDLENGTH_9B) &&
            (pHUsart->Init.Parity == USART_PARITY_NONE) )
        {
            WRITE_REG_MASK(pHUsart->Instance->DR, USART_DR_9BIT, *ptr_16bits);

            ptr_16bits++;
        }
        else
        {
            WRITE_REG_MASK(pHUsart->Instance->DR, USART_DR_8BIT, *ptr_8bits);

            ptr_8bits++;
        }

        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TXE, RESET, tickstart, Timeout);
        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }
    }

    //Wait module transmit last data.
    __HAL_USART_CLEAR_FLAG(pHUsart, USART_FLAG_TC);

    rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TC, RESET, tickstart, Timeout);

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return rval;

}


/**
  * @brief  Synchronous or Full-Duplex Receive an amount of data in blocking mode.
  * @note   To receive synchronous data, dummy data are simultaneously transmitted.
  * @note   When USART parity is not enabled, and word length is configured to 9 bits,
  *         the received data is handled as a set of uint16. In this case, Size must indicate the number
  *         of uint16 available through pRxData.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pRxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be received.
  * @param  Timeout Timeout duration.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Receive(USART_HandleTypeDef *pHUsart, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
{
    HAL_StatusTypeDef rval    = HAL_OK;
    uint32_t tickstart          = 0U;
    uint8_t  *ptr_8bits         = (uint8_t *)pRxData;
    uint16_t *ptr_16bits        = (uint16_t *)pRxData;


    if( pHUsart->RxState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }

    //Check input parameters valid.
    if( (!pRxData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    __HAL_LOCK(pHUsart);

    pHUsart->RxState    = HAL_USART_STATE_BUSY_RX;
    pHUsart->ErrorCode  = HAL_USART_ERROR_NONE;

    __HAL_USART_CLEAR_PEFLAG(pHUsart);

    tickstart = HAL_GetTick();
    pHUsart->RxXferCount = Size;
    pHUsart->RxXferSize = Size;

    while( pHUsart->RxXferCount )
    {
        uint16_t tmp            = 0U;

        //If the module is working in synchronous mode, it sends a synchronous clock signal.
        if( (pHUsart->Instance->CR2 & USART_CR2_CLKEN) )
        {
            _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TXE, RESET, tickstart, Timeout);

            pHUsart->Instance->DR = DUMMY_DATA;
        }

        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_RXNE, RESET, tickstart, Timeout);
        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }

        if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_PE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_PARITY;
        }

        if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_FE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_FE;
        }

        tmp = (pHUsart->Instance->DR & USART_DR_9BIT);

        //When word length is 9bits and no parity data, pRxData will be used as an unsigned 16-bit data pointer.
        if( (pHUsart->Init.WordLength == USART_WORDLENGTH_9B) &&
            (pHUsart->Init.Parity == USART_PARITY_NONE) )
        {
            *ptr_16bits = (uint16_t)(tmp & USART_DR_9BIT);

            ptr_16bits++;
        }
        else if( ((pHUsart->Init.WordLength == USART_WORDLENGTH_9B) &&
            (pHUsart->Init.Parity != USART_PARITY_NONE) ) ||
            ((pHUsart->Init.WordLength == USART_WORDLENGTH_8B) &&
            ((pHUsart->Init.Parity == USART_PARITY_NONE))) )
        {
            *ptr_8bits = (uint8_t)(tmp & USART_DR_8BIT);

            ptr_8bits++;
        }
        else
        {
            *ptr_8bits = (uint8_t)(tmp & USART_DR_7BIT);

            ptr_8bits++;
        }

        pHUsart->RxXferCount--;
    }

    pHUsart->RxState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return rval;
}


/**
  * @brief  Synchronous Send and Receive an amount of data in synchronous mode (blocking mode).
  * @note   When USART parity is not enabled, and Word Length is configured to 9 bits,
  *         the sent data and the received data are handled as sets of uint16. In this case, Size must indicate the number
  *         of uint16 available through pTxData and through pRxData.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pTxData Pointer to TX data buffer (uint8 or uint16 data elements).
  * @param  pRxData Pointer to RX data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent (same amount to be received).
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_TransmitReceive(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
{
    HAL_StatusTypeDef rval    = HAL_OK;
    uint32_t tickstart          = 0U;
    uint16_t *pTxData16bits     = NULL;
    uint16_t *pRxData16bits     = NULL;
    uint8_t  *pTxData8bits      = NULL;
    uint8_t  *pRxData8bits      = NULL;


    if( (pHUsart->gState != HAL_USART_STATE_READY) ||
        (pHUsart->RxState != HAL_USART_STATE_READY) )
    {
        return HAL_BUSY;
    }

    //Check input parameters valid.
    if( (!pTxData) ||
        (!pRxData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->RxState = HAL_USART_STATE_BUSY_TX_RX;

    __HAL_USART_CLEAR_PEFLAG(pHUsart);

    tickstart = HAL_GetTick();

    pHUsart->TxXferCount = Size;
    pHUsart->TxXferSize = Size;
    pHUsart->RxXferCount = Size;
    pHUsart->RxXferSize = Size;

    //When word length is 9bits and no parity data, pRxData will be used as an unsigned 16-bit data pointer.
    if( (pHUsart->Init.WordLength == USART_WORDLENGTH_9B) &&
        (pHUsart->Init.Parity == USART_PARITY_NONE) )
    {
        pTxData16bits = (uint16_t *)pTxData;
        pRxData16bits = (uint16_t *)pRxData;
    }
    else
    {
        pTxData8bits = (uint8_t *)pTxData;
        pRxData8bits = (uint8_t *)pRxData;
    }

    _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TXE, RESET, tickstart, Timeout);

    while( pHUsart->TxXferCount )
    {
        uint16_t tmp            = 0U;

        pHUsart->TxXferCount--;

        if( pTxData8bits )
        {
            WRITE_REG_MASK(pHUsart->Instance->DR, USART_DR_8BIT, *pTxData8bits);

            pTxData8bits++;
        }
        else
        {
            WRITE_REG_MASK(pHUsart->Instance->DR, USART_DR_9BIT, *pTxData16bits);

            pTxData16bits++;
        }

        //if the time consumed during data transmission is longer than the preset value, stops data transmission.
        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TC, RESET, tickstart, Timeout);
        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }

        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_RXNE, RESET, tickstart, Timeout);
        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }

        tmp = (pHUsart->Instance->DR & USART_DR_9BIT);

        pHUsart->RxXferCount--;

        if( pRxData8bits )
        {
            *pRxData8bits = (uint8_t)tmp;

            pRxData8bits++;

        }
        else
        {
            *pRxData16bits = (uint16_t)tmp;

            pRxData16bits++;
        }
    }

    pHUsart->gState = HAL_USART_STATE_READY;
    pHUsart->RxState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return rval;
}


/**
  * @brief  Send an amount of data in non-blocking mode.
  * @note   When USART parity is not enabled, and Word Length is configured to 9 bits,
  *         the sent data is handled as a set of uint16. In this case, Size must indicate the number
  *         of uint16 provided through pTxData.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pTxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent.
  * @retval HAL status
  * @note   The USART errors are not managed to avoid the overrun error.
  */
HAL_StatusTypeDef HAL_USART_Transmit_IT(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint16_t Size)
{
    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }

    if( (!pTxData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHUsart);

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;
    pHUsart->gState = HAL_USART_STATE_BUSY_TX;

    pHUsart->pTxBuffPtr = pTxData;
    pHUsart->TxXferCount = Size;
    pHUsart->TxXferSize = Size;

    __HAL_UNLOCK(pHUsart);

    //Start transmit data, enable TXE nvic interrupt.
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_TXEIE_Msk);

    return HAL_OK;
}



/**
  * @brief  Receive an amount of data in non-blocking mode.
  * @note   To receive synchronous data, dummy data are simultaneously transmitted.
  * @note   When USART parity is not enabled, and Word Length is configured to 9 bits,
  *         the received data is handled as a set of uint16. In this case, Size must indicate the number
  *         of uint16 available through pRxData.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pRxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be received.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Receive_IT(USART_HandleTypeDef *pHUsart, uint8_t *pRxData, uint16_t Size)
{
    if( pHUsart->RxState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }

    if( (!pRxData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHUsart);

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    pHUsart->RxState = HAL_USART_STATE_BUSY_RX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->pRxBuffPtr = pRxData;
    pHUsart->RxXferCount = Size;
    pHUsart->RxXferSize = Size;

    __HAL_UNLOCK(pHUsart);

    __HAL_USART_CLEAR_PEFLAG(pHUsart);

    //Start receive data, enable RXNE/PE/FE nvic interrupt.
    SET_BIT(pHUsart->Instance->CR3, USART_CR3_EIE_Msk);
    SET_BIT(pHUsart->Instance->CR1, (USART_CR1_RXNEIE_Msk | USART_CR1_PEIE_Msk));

    //If the module is working in synchronous mode, it sends a synchronous clock signal.
    if( (pHUsart->Instance->CR2 & USART_CR2_CLKEN) )
    {
        WRITE_REG(pHUsart->Instance->DR, DUMMY_DATA);
    }

    return HAL_OK;
}



/**
  * @brief  Synchronous Send and Receive an amount of data in synchronous mode (non-blocking).
  * @note   When USART parity is not enabled, and Word Length is configured to 9 bits,
  *         the sent data and the received data are handled as sets of uint16. In this case, size must indicate the number
  *         of uint16 available through pTxData and through pRxData.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pTxData Pointer to TX data buffer (uint8 or uint16 data elements).
  * @param  pRxData Pointer to RX data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent (same amount to be received).
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_TransmitReceive_IT(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint8_t *pRxData,  uint16_t Size)
{
    if( (pHUsart->gState != HAL_USART_STATE_READY) ||
        (pHUsart->RxState != HAL_USART_STATE_READY) )
    {
        return HAL_BUSY;
    }

    if( (!pTxData) ||
        (!pRxData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHUsart);

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    pHUsart->gState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->RxState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->pTxBuffPtr = pTxData;
    pHUsart->pRxBuffPtr = pRxData;
    pHUsart->TxXferCount = Size;
    pHUsart->TxXferSize = Size;
    pHUsart->RxXferCount = Size;
    pHUsart->RxXferSize = Size;

    __HAL_UNLOCK(pHUsart);

    __HAL_USART_CLEAR_PEFLAG(pHUsart);

    SET_BIT(pHUsart->Instance->CR3, USART_CR3_EIE_Msk);
    SET_BIT(pHUsart->Instance->CR1, (USART_CR1_TXEIE_Msk | USART_CR1_RXNEIE_Msk | USART_CR1_PEIE_Msk));

    return HAL_OK;
}



/**
  * @brief  Abort ongoing transfer (blocking mode).
  * @param  pHUsart USART handle.
  * @note   This procedure could be used for aborting any ongoing transfer.
  *         This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Abort(USART_HandleTypeDef *pHUsart)
{
    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_TCIE_Msk | USART_CR1_TXEIE_Msk | USART_CR1_RXNEIE_Msk | USART_CR1_PEIE_Msk));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_EIE_Msk | USART_CR3_DMAT_Msk | USART_CR3_DMAR_Msk));

    pHUsart->TxXferCount = 0U;
    pHUsart->RxXferCount = 0U;

    pHUsart->gState = HAL_USART_STATE_READY;
    pHUsart->RxState = HAL_USART_STATE_READY;

    return HAL_OK;
}


/**
  * @brief  Abort ongoing transmit data.(blocking mode)
  * @param  pHUsart USART handle.
  * @note   This procedure could be used for aborting any ongoing transfer.
  *         This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_AbortTransmit(USART_HandleTypeDef *pHUsart)
{
    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_TCIE_Msk | USART_CR1_TXEIE_Msk));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAT_Msk));

    pHUsart->TxXferCount = 0U;

    pHUsart->gState = HAL_USART_STATE_READY;

    return HAL_OK;
}


/**
  * @brief  Abort ongoing receive data.(blocking mode)
  * @param  pHUsart USART handle.
  * @note   This procedure could be used for aborting any ongoing transfer.
  *         This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_AbortReceive(USART_HandleTypeDef *pHUsart)
{
    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_RXNEIE_Msk | USART_CR1_PEIE_Msk));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_EIE_Msk | USART_CR3_DMAR_Msk));

    pHUsart->RxXferCount = 0U;

    pHUsart->RxState = HAL_USART_STATE_READY;

    return HAL_OK;
}


/**
  * @brief  Abort ongoing transfer (interrupt mode).
  * @param  pHUsart USART handle.
  * @note     This procedure could be used for aborting any ongoing transfer.
  *           This procedure is executed in Interrupt mode, meaning that abort procedure could be
  *         considered as completed only when user abort complete callback is executed (not when exiting function).
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Abort_IT(USART_HandleTypeDef *pHUsart)
{
    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_TCIE_Msk | USART_CR1_TXEIE_Msk | USART_CR1_RXNEIE_Msk | USART_CR1_PEIE_Msk));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_EIE_Msk | USART_CR3_DMAT_Msk | USART_CR3_DMAR_Msk));

    pHUsart->TxXferCount = 0U;
    pHUsart->RxXferCount = 0U;

    pHUsart->gState = HAL_USART_STATE_READY;
    pHUsart->RxState = HAL_USART_STATE_READY;

    HAL_USART_AbortCpltCallback(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Abort ongoing transmit data (interrupt mode).
  * @param  pHUsart USART handle.
  * @note     This procedure could be used for aborting any ongoing transfer.
  *           This procedure is executed in Interrupt mode, meaning that abort procedure could be
  *         considered as completed only when user abort complete callback is executed (not when exiting function).
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_AbortTransmit_IT(USART_HandleTypeDef *pHUsart)
{
    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_TCIE_Msk | USART_CR1_TXEIE_Msk));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAT_Msk));

    pHUsart->TxXferCount = 0U;

    pHUsart->gState = HAL_USART_STATE_READY;

    HAL_USART_AbortTxCpltCallback(pHUsart);

    return HAL_OK;
}


/**
  * @brief  Abort ongoing receive data (interrupt mode).
  * @param  pHUsart USART handle.
  * @note     This procedure could be used for aborting any ongoing transfer.
  *           This procedure is executed in Interrupt mode, meaning that abort procedure could be
  *         considered as completed only when user abort complete callback is executed (not when exiting function).
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_AbortReceive_IT(USART_HandleTypeDef *pHUsart)
{
    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_RXNEIE_Msk | USART_CR1_PEIE_Msk));
    CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_EIE_Msk | USART_CR3_DMAR_Msk));

    pHUsart->RxXferCount = 0U;

    pHUsart->RxState = HAL_USART_STATE_READY;

    HAL_USART_AbortRxCpltCallback(pHUsart);

    return HAL_OK;
}



/**
  * @brief  This function handles USART interrupt request.
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
void HAL_USART_IRQHandler(USART_HandleTypeDef *pHUsart)
{
    uint32_t interruptsr    = pHUsart->Instance->SR;
    uint32_t reg1iten       = pHUsart->Instance->CR1;
    uint32_t reg2iten       = pHUsart->Instance->CR2;
    uint32_t reg3iten       = pHUsart->Instance->CR3;
    uint32_t errorflag      = 0U;

    //Check whether there is an error that needs to be handled.
    errorflag = (interruptsr) & (USART_FLAG_PE | USART_FLAG_FE | USART_FLAG_NE | USART_FLAG_ORE);

    //===================================Receive data handle=======================================
    if( (reg1iten & USART_CR1_RXNEIE) &&
        (interruptsr & USART_FLAG_RXNE) )
    {
        if(pHUsart->RxXferCount)
        {
            if(pHUsart->RxState == HAL_USART_STATE_BUSY_RX)
            {
                _USART_Receive_IT(pHUsart);
            }
            if(pHUsart->RxState == HAL_USART_STATE_BUSY_TX_RX)
            {
                _USART_TransmitReceive_IT(pHUsart);
            }
        }

        //End receive data, call the callback function.
        if( (!pHUsart->RxXferCount) )
        {
            if(pHUsart->RxState == HAL_USART_STATE_BUSY_RX)
            {
                pHUsart->RxState = HAL_USART_STATE_READY;

                //if module work on half-duplex mode.
                if( (reg3iten & USART_CR3_HDSEL) )
                {
                    HAL_USART_RxHalfCpltCallback(pHUsart);
                }
                else
                {
                    HAL_USART_RxCpltCallback(pHUsart);  //USART work on asynchronous or synchronous mode.
                }

            }
            if(pHUsart->RxState == HAL_USART_STATE_BUSY_TX_RX)
            {
                pHUsart->gState = HAL_USART_STATE_READY;
                pHUsart->RxState = HAL_USART_STATE_READY;

                HAL_USART_TxRxCpltCallback(pHUsart);    //USART work on asynchronous or synchronous mode.
            }
        }
        else
        {
            if( (reg2iten & USART_CR2_CLKEN) &&
                (pHUsart->RxState == HAL_USART_STATE_BUSY_RX) )
            {
                WRITE_REG(pHUsart->Instance->DR, DUMMY_DATA);
            }
        }

        if( (!errorflag) )
        {
            return;
        }
    }

    if( errorflag )
    {
        //===================================PE interrupt handle=======================================
        if( (errorflag & USART_FLAG_PE) &&
            (reg1iten & USART_CR1_PEIE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_PARITY;
        }

        //===================================FE interrupt handle=======================================
        if( (errorflag & USART_FLAG_FE) &&
            (reg3iten & USART_CR3_EIE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_FE;
        }

        //===================================NE interrupt handle=======================================
        if( (errorflag & USART_FLAG_NE) &&
            (reg3iten & USART_CR3_EIE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_NE;
        }

        //===================================ORE interrupt handle=======================================
        if( (errorflag & USART_FLAG_ORE) &&
            ( (reg1iten & USART_CR1_RXNEIE) &&
            (reg3iten & USART_CR3_EIE) ) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_ORE;
        }

        __HAL_USART_CLEAR_FEFLAG(pHUsart);

        if( (reg1iten & USART_CR1_PEIE) ||
            (reg3iten & USART_CR3_EIE) )
        {
            HAL_USART_ErrorCallback(pHUsart);
        }
    }

    //===================================Transmit data handle=======================================
    if( (interruptsr & USART_FLAG_TXE) &&
        (reg1iten & USART_CR1_TXEIE) )
    {
        if( pHUsart->TxXferCount )
        {
            if(pHUsart->gState == HAL_USART_STATE_BUSY_TX)
            {
                _USART_Transmit_IT(pHUsart);
            }
            if(pHUsart->gState == HAL_USART_STATE_BUSY_TX_RX)
            {
               _USART_TransmitReceive_IT(pHUsart);
            }
        }

        if( (!pHUsart->TxXferCount) )
        {
            if(pHUsart->gState == HAL_USART_STATE_BUSY_TX)
            {
                SET_BIT(pHUsart->Instance->CR1, USART_CR1_TCIE);
            }
        }

        return;
    }

    //===================================End transmit data handle=======================================
    if( (interruptsr & USART_FLAG_TC) &&
        (reg1iten & USART_CR1_TCIE) )
    {
        CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_TCIE);

        pHUsart->gState = HAL_USART_STATE_READY;


        //if module work on half-duplex mode.
        if( (reg3iten & USART_CR3_HDSEL) )
        {
            HAL_USART_TxHalfCpltCallback(pHUsart);
        }
        else
        {
            HAL_USART_TxCpltCallback(pHUsart);  //USART work on asynchronous or synchronous mode.
        }
        return;
    }

    //=====================================CTS interrupt handle========================================
    if( (interruptsr & USART_FLAG_CTS) &&
        (reg3iten & USART_CR3_CTSIE) )
    {
        __HAL_USART_CLEAR_FLAG(pHUsart, USART_FLAG_CTS);

        HAL_USART_CTSCallback(pHUsart);
    }

    //=====================================LBD interrupt handle========================================
    if( (interruptsr & USART_FLAG_LBD) &&
        (reg2iten & USART_CR2_LBDIE) )
    {
        __HAL_USART_CLEAR_FLAG(pHUsart, USART_FLAG_LBD);

        HAL_USART_LBDCallback(pHUsart);
    }

    //====================================IDLE interrupt handle========================================
    if( (interruptsr & USART_FLAG_IDLE) &&
        (reg1iten & USART_CR1_IDLEIE) )
    {
        __HAL_USART_CLEAR_IDLEFLAG(pHUsart);

        HAL_USART_IDLECallback(pHUsart);
    }
}




/**
  * @brief  Tx Transfer completed callbacks.
  * @param  pHUsart Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_TxCpltCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
            the HAL_USART_TxCpltCallback could be implemented in the user file
    */
}

/**
  * @brief  Tx Half Transfer completed callbacks.
  * @param  pHUsart Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_TxHalfCpltCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_TxHalfCpltCallback could be implemented in the user file
    */
}

/**
  * @brief  Rx Transfer completed callbacks.
  * @param  pHUsart Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_RxCpltCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_RxCpltCallback could be implemented in the user file
    */
}

/**
  * @brief  Rx Half Transfer completed callbacks.
  * @param  pHUsart Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_RxHalfCpltCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_RxHalfCpltCallback could be implemented in the user file
    */
}

/**
  * @brief  Tx/Rx Transfers completed callback for the non-blocking process.
  * @param  pHUsart Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_TxRxCpltCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_TxRxCpltCallback could be implemented in the user file
    */
}

/**
  * @brief  USART error callbacks.
  * @param  pHUsart Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_ErrorCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_ErrorCallback could be implemented in the user file
    */
}

/**
  * @brief  USART CTS interrupt callbacks.
  * @param  pHUsart Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_CTSCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_ErrorCallback could be implemented in the user file
    */
}

/**
  * @brief  USART LBD interrupt callbacks.
  * @param  pHUsart Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_LBDCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_ErrorCallback could be implemented in the user file
    */
}

/**
  * @brief  USART IDLE interrupt callbacks.
  * @param  pHUsart Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_IDLECallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_ErrorCallback could be implemented in the user file
    */
}

/**
  * @brief  USART Abort Complete callback.
  * @param  pHUsart USART handle.
  * @retval None
  */
__weak void HAL_USART_AbortCpltCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);

    /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_USART_AbortCpltCallback can be implemented in the user file.
    */
}

/**
  * @brief  USART Transmit Abort Complete callback.
  * @param  pHUsart USART handle.
  * @retval None
  */
__weak void HAL_USART_AbortTxCpltCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);

    /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_USART_AbortTxCpltCallback can be implemented in the user file.
    */
}

/**
  * @brief  USART Receive Abort Complete callback.
  * @param  pHUsart USART handle.
  * @retval None
  */
__weak void HAL_USART_AbortRxCpltCallback(USART_HandleTypeDef *pHUsart)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHUsart);

    /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_USART_AbortRxCpltCallback can be implemented in the user file.
    */
}



/**
  * @brief  Transmits break characters on LIN mode.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_LIN_SendBreak(USART_HandleTypeDef *pHUsart)
{
    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }

    if( !(pHUsart->Instance->CR2 & USART_CR2_LINEN) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_LIN_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_TX;

    SET_BIT(pHUsart->Instance->CR1, USART_CR1_SBK_Msk);

    //Wait USART sended break data.
    while( (READ_BIT(pHUsart->Instance->CR1, USART_CR1_SBK) == USART_CR1_SBK) );

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Enters the USART in mute mode.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_MultiProcessor_EnterMuteMode(USART_HandleTypeDef *pHUsart)
{
    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY;

    SET_BIT(pHUsart->Instance->CR1, USART_CR1_RWU_Msk);

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Exits the USART mute mode: wake up software.
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_MultiProcessor_ExitMuteMode(USART_HandleTypeDef *pHUsart)
{
    uint32_t tmp = 0U;

    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY;

    tmp = pHUsart->Instance->CR1;

    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_RE);

    do{
        CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_RWU_Msk);
    }while( READ_BIT(pHUsart->Instance->CR1, USART_CR1_RWU) == USART_CR1_RWU );

    if( (tmp & USART_CR1_RE) == USART_CR1_RE )
    {
        SET_BIT(pHUsart->Instance->CR1, USART_CR1_RE);
    }

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Enables the USART transmitter and disables the USART receiver.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_HalfDuplex_EnableTransmitter(USART_HandleTypeDef *pHUsart)
{
    if( (pHUsart->gState != HAL_USART_STATE_READY) &&
        (pHUsart->RxState != HAL_USART_STATE_READY) )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_HALFDUPLEX_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY;

    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_RE);
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_TE_Msk);
    pHUsart->Init.Mode = USART_MODE_TX;

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Enables the UART receiver and disables the USART transmitter.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_HalfDuplex_EnableReceiver(USART_HandleTypeDef *pHUsart)
{
    if( (pHUsart->gState != HAL_USART_STATE_READY) &&
        (pHUsart->RxState != HAL_USART_STATE_READY) )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_HALFDUPLEX_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY;

    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_TE);
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_RE_Msk);
    pHUsart->Init.Mode = USART_MODE_RX;

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}




/**
  * @brief  Returns the USART state.
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART module.
  * @retval HAL state
  */
HAL_USART_StateTypeDef HAL_USART_GetState(USART_HandleTypeDef *pHUsart)
{
    HAL_USART_StateTypeDef tmp = HAL_USART_STATE_RESET;
    tmp |= pHUsart->gState;
    tmp |= pHUsart->RxState;

    return tmp;
}



/**
  * @brief  Return the USART error code
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART.
  * @retval USART Error Code
  */
uint32_t HAL_USART_GetError(USART_HandleTypeDef *pHUsart)
{
    return (uint32_t)(pHUsart->ErrorCode);
}

//=============================================================================
//                         Asynchronous Mode Function
//=============================================================================
/**
  * @brief    In asynchronous mode, the function of sending and receiving data
  *         asynchronously is realized.
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART.
  * @param  pTxData  Pointer to transmit data buff(uint8 or uint16 data elements).
  * @param  TxSize   Amount of data elements (uint8 or uint16) to be sent.
  * @param  pRxData  Pointer to receive data buff(uint8 or uint16 data elements).
  * @param  RxSize   Amount of data elements (uint8 or uint16) to be received.
  * @param  Timeout  Timeout duration.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Asynchronous_TransmitReceive(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint16_t TxSize, uint8_t *pRxData, uint16_t RxSize, uint32_t Timeout)
{
    uint8_t     *ptx8bits   = NULL;
    uint8_t     *prx8bits   = NULL;
    uint16_t    *ptx16bits  = NULL;
    uint16_t    *prx16bits  = NULL;
    uint32_t    tickstart   = 0U;
    uint16_t    tmp         = 0U;

    if( (pHUsart->gState != HAL_USART_STATE_READY) ||
        (pHUsart->RxState != HAL_USART_STATE_READY) )
    {
        return HAL_BUSY;
    }

    if( (!pTxData) ||
        (!pRxData) ||
        (!TxSize) ||
        (!RxSize) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));
    assert_param(IS_USART_STOPBITS(pHUsart->Init.StopBits));
    assert_param(IS_USART_MODE(pHUsart->Init.Mode));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->RxState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->TxXferCount = TxSize;
    pHUsart->TxXferSize = TxSize;
    pHUsart->RxXferCount = RxSize;
    pHUsart->RxXferSize = RxSize;

    if( (pHUsart->Init.Parity == USART_PARITY_NONE) &&
        (pHUsart->Init.WordLength == USART_WORDLENGTH_9B) )
    {
        ptx16bits = (uint16_t *)pTxData;
        prx16bits = (uint16_t *)pRxData;
    }
    else
    {
        ptx8bits = (uint8_t *)pTxData;
        prx8bits = (uint8_t *)pRxData;
    }

    tickstart = HAL_GetTick();

    __HAL_USART_CLEAR_PEFLAG(pHUsart);

    while( ( (pHUsart->TxXferCount) || (pHUsart->RxXferCount) ) &&
            ( (HAL_GetTick() - tickstart) < Timeout) )
    {
        if( (__HAL_USART_GET_FLAG(pHUsart, USART_FLAG_RXNE)) &&
            (pHUsart->RxXferCount) )
        {
            if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_PE) )
            {
                pHUsart->ErrorCode |= HAL_USART_ERROR_PARITY;
            }

            if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_FE) )
            {
                pHUsart->ErrorCode |= HAL_USART_ERROR_FE;
            }

            tmp = (uint16_t)pHUsart->Instance->DR;

            pHUsart->RxXferCount--;

            if( prx8bits )
            {
                *prx8bits = (uint8_t)tmp;

                prx8bits++;
            }
            else
            {
                *prx16bits = tmp;

                prx16bits++;
            }
        }

        if( (__HAL_USART_GET_FLAG(pHUsart, USART_FLAG_TC)) &&
            (pHUsart->TxXferCount) )
        {
            if( ptx8bits )
            {
                tmp = ((uint16_t)(*ptx8bits) & USART_DR_8BIT);

                ptx8bits++;
            }
            else
            {
                tmp = ((uint16_t)(*ptx16bits) & USART_DR_9BIT);

                ptx16bits++;
            }

            pHUsart->TxXferCount--;

            WRITE_REG_MASK(pHUsart->Instance->DR, USART_DR_DR_Msk, tmp);
        }
    }

    pHUsart->gState = HAL_USART_STATE_READY;
    pHUsart->RxState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    if( (pHUsart->TxXferCount) ||
        (pHUsart->RxXferCount) )
    {
        return HAL_TIMEOUT;
    }
    if( pHUsart->ErrorCode != HAL_USART_ERROR_NONE )
    {
        return HAL_ERROR;
    }

    return HAL_OK;
}


/**
  * @brief    In asynchronous mode, data is sent and received asynchronously from
  *         end to data.
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART.
  * @param  pTxData  Pointer to transmit data buff(uint8 or uint16 data elements).
  * @param  TxSize   Amount of data elements (uint8 or uint16) to be sent.
  * @param  pRxData  Pointer to receive data buff(uint8 or uint16 data elements).
  * @param  RxSize   Amount of data elements (uint8 or uint16) to be received.
  * @param  Timeout  Timeout duration.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Asynchronous_ReceiveTransmit(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint16_t TxSize, uint8_t *pRxData, uint16_t RxSize, uint32_t Timeout)
{
    HAL_StatusTypeDef   rval      = HAL_OK;
    uint8_t             *ptx8bits   = NULL;
    uint8_t             *prx8bits   = NULL;
    uint16_t            *ptx16bits  = NULL;
    uint16_t            *prx16bits  = NULL;
    uint32_t            tickstart   = 0U;
    uint16_t            tmp         = 0U;

    if( (pHUsart->gState != HAL_USART_STATE_READY) ||
        (pHUsart->RxState != HAL_USART_STATE_READY) )
    {
        return HAL_BUSY;
    }

    if( (!pTxData) ||
        (!pRxData) ||
        (!TxSize) ||
        (!RxSize) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));
    assert_param(IS_USART_STOPBITS(pHUsart->Init.StopBits));
    assert_param(IS_USART_MODE(pHUsart->Init.Mode));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->RxState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->TxXferCount = TxSize;
    pHUsart->TxXferSize = TxSize;
    pHUsart->RxXferCount = RxSize;
    pHUsart->RxXferSize = RxSize;

    if( (pHUsart->Init.Parity == USART_PARITY_NONE) &&
        (pHUsart->Init.WordLength == USART_WORDLENGTH_9B) )
    {
        ptx16bits = (uint16_t *)pTxData;
        prx16bits = (uint16_t *)pRxData;
    }
    else
    {
        ptx8bits = (uint8_t *)pTxData;
        prx8bits = (uint8_t *)pRxData;
    }

    __HAL_USART_CLEAR_PEFLAG(pHUsart);

    tickstart = HAL_GetTick();

    rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_RXNE, RESET, tickstart, Timeout);
    if( rval == HAL_OK )
    {
        tmp = (uint16_t)READ_REG(pHUsart->Instance->DR);

        pHUsart->RxXferCount--;

        if( prx8bits )
        {
            *prx8bits = (uint8_t)tmp;

            prx8bits++;
        }
        else
        {
            *prx16bits = (uint16_t)tmp;

            prx16bits++;
        }
    }

    while( ( (pHUsart->TxXferCount) ||
            (pHUsart->RxXferCount) ) &&
            ((HAL_GetTick() - tickstart) < Timeout) )
    {
        if( (__HAL_USART_GET_FLAG(pHUsart, USART_FLAG_RXNE)) && (pHUsart->RxXferCount) )
        {
            if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_PE) )
            {
                pHUsart->ErrorCode |= HAL_USART_ERROR_PARITY;
            }

            if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_FE) )
            {
                pHUsart->ErrorCode |= HAL_USART_ERROR_FE;
            }

            tmp = (uint16_t)pHUsart->Instance->DR;

            pHUsart->RxXferCount--;

            if( prx8bits )
            {
                *prx8bits = (uint8_t)tmp;

                prx8bits++;
            }
            else
            {
                *prx16bits = tmp;

                prx16bits++;
            }
        }

        if( (__HAL_USART_GET_FLAG(pHUsart, USART_FLAG_TC)) && (pHUsart->TxXferCount) )
        {
            if( ptx8bits )
            {
                tmp = ((uint16_t)(*ptx8bits) & USART_DR_8BIT);

                ptx8bits++;
            }
            else
            {
                tmp = ((uint16_t)(*ptx16bits) & USART_DR_9BIT);

                ptx16bits++;
            }

            pHUsart->TxXferCount--;

            WRITE_REG_MASK(pHUsart->Instance->DR, USART_DR_DR_Msk, tmp);
        }
    }

    pHUsart->gState = HAL_USART_STATE_READY;
    pHUsart->RxState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    if( (pHUsart->TxXferCount) || (pHUsart->RxXferCount) )
    {
        return HAL_TIMEOUT;
    }
    if( pHUsart->ErrorCode != HAL_USART_ERROR_NONE )
    {
        return HAL_ERROR;
    }

    return HAL_OK;
}



//=============================================================================
//                         Half-Duplex Mode Function
//=============================================================================
/**
  * @brief  Send data in single-line half-duplex mode.
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART.
  * @param  pData    Pointer to transmit data buff(uint8 or uint16 data elements).
  * @param  Size     Amount of data elements (uint8 or uint16) to be sent.
  * @param  Timeout  Timeout duration.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_HalfDuplex_Transmit(USART_HandleTypeDef *pHUsart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
    HAL_StatusTypeDef   rval      = HAL_OK;
    uint8_t             *ptr8bits   = NULL;
    uint16_t            *ptr16bits  = NULL;
    uint32_t            tickstart   = 0U;

    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }

    if( (!pData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_HALFDUPLEX_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_TX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->TxXferCount = Size;
    pHUsart->TxXferSize = Size;

    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_RE_Msk);
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_TE_Msk);

    if( (pHUsart->Init.Parity == USART_PARITY_NONE) &&
        (pHUsart->Init.WordLength) )
    {
        ptr16bits = (uint16_t *)pData;
    }
    else
    {
        ptr8bits = (uint8_t *)pData;
    }

    tickstart = HAL_GetTick();

    while( pHUsart->TxXferCount )
    {
        pHUsart->TxXferCount--;

        if( ptr8bits )
        {
            WRITE_REG_MASK(pHUsart->Instance->DR, USART_DR_8BIT, *ptr8bits);

            ptr8bits++;
        }
        else
        {
            WRITE_REG_MASK(pHUsart->Instance->DR, USART_DR_9BIT, *ptr16bits);

            ptr16bits++;
        }

        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TXE, RESET, tickstart, Timeout);
        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }
    }

    rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TC, RESET, tickstart, Timeout);

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return rval;
}


/**
  * @brief  Received data in single-line half-duplex mode.
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART.
  * @param  pData    Pointer to receive data buff(uint8 or uint16 data elements).
  * @param  Size     Amount of data elements (uint8 or uint16) to be receive.
  * @param  Timeout  Timeout duration.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_HalfDuplex_Receive(USART_HandleTypeDef *pHUsart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
    HAL_StatusTypeDef   rval      = HAL_OK;
    uint8_t             *ptr8bits   = NULL;
    uint16_t            *ptr16bits  = NULL;
    uint32_t            tickstart   = 0U;
    uint16_t            tmp         = 0U;

    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }

    if( (!pData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_HALFDUPLEX_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_RX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->RxXferCount = Size;
    pHUsart->RxXferSize = Size;

    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_TE_Msk);
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_RE_Msk);

    if( (pHUsart->Init.Parity == USART_PARITY_NONE) &&
        (pHUsart->Init.WordLength) )
    {
        ptr16bits = (uint16_t *)pData;
    }
    else
    {
        ptr8bits = (uint8_t *)pData;
    }

    __HAL_USART_CLEAR_PEFLAG(pHUsart);

    tickstart = HAL_GetTick();

    while( pHUsart->RxXferCount )
    {
        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_RXNE, RESET, tickstart, Timeout);

        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }

        if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_PE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_PARITY;
        }
        if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_FE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_FE;
        }

        tmp = READ_REG(pHUsart->Instance->DR);

        pHUsart->RxXferCount--;

        if( ptr8bits )
        {
            *ptr8bits = (uint8_t)tmp;

            ptr8bits++;
        }
        else
        {
            *ptr16bits = (uint16_t)tmp;

            ptr16bits++;
        }
    }

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return rval;
}


/**
  * @brief    In single-line half-duplex mode, a certain amount of data is sent
  *         and then a certain amount of data is received.
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART.
  * @param  pTxData  Pointer to transmit data buff(uint8 or uint16 data elements).
  * @param  TxSize   Amount of data elements (uint8 or uint16) to be sent.
  * @param  pRxData  Pointer to receive data buff(uint8 or uint16 data elements).
  * @param  RxSize   Amount of data elements (uint8 or uint16) to be received.
  * @param  Timeout  Timeout duration.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_HalfDuplex_TransmitReceive(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint16_t TxSize, uint8_t *pRxData, uint16_t RxSize, uint32_t Timeout)
{
    HAL_StatusTypeDef   rval        = HAL_OK;
    uint8_t             *ptx8bits   = NULL;
    uint8_t             *prx8bits   = NULL;
    uint16_t            *ptx16bits  = NULL;
    uint16_t            *prx16bits  = NULL;
    uint32_t            tickstart   = 0U;
    uint16_t            tmp         = 0U;

    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }
    if( (!pTxData) ||
        (!pRxData) ||
        (!TxSize) ||
        (!RxSize) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_HALFDUPLEX_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->TxXferCount = TxSize;
    pHUsart->TxXferSize = TxSize;
    pHUsart->RxXferCount = RxSize;
    pHUsart->RxXferSize = RxSize;

    __HAL_USART_CLEAR_FEFLAG(pHUsart);

    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_RE_Msk);
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_TE_Msk);

    if( (pHUsart->Init.Parity == USART_PARITY_NONE) &&
        (pHUsart->Init.WordLength == USART_WORDLENGTH_9B) )
    {
        ptx16bits = (uint16_t *)pTxData;
        prx16bits = (uint16_t *)pRxData;
    }
    else
    {
        ptx8bits = (uint8_t *)pTxData;
        prx8bits = (uint8_t *)pRxData;
    }

    while( pHUsart->TxXferCount )
    {
        if( ptx8bits )
        {
            WRITE_REG_MASK(pHUsart->Instance->CR1, USART_DR_8BIT, *ptx8bits);

            ptx8bits++;
        }
        else
        {
            WRITE_REG_MASK(pHUsart->Instance->CR2, USART_DR_9BIT, *ptx16bits);

            ptx16bits++;
        }

        pHUsart->TxXferCount--;

        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_RXNE, RESET, tickstart, Timeout);

        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }
    }

    _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TC, RESET, tickstart, Timeout);

    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_TE_Msk);
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_RE_Msk);

    while( pHUsart->RxXferCount )
    {
        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_RXNE, RESET, tickstart, Timeout);
        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }

        if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_PE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_PARITY;
        }
        if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_FE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_FE;
        }

        tmp = READ_REG(pHUsart->Instance->DR);

        pHUsart->RxXferCount--;

        if( prx8bits )
        {
            *prx8bits = (uint8_t)tmp;

            prx8bits++;
        }
        else
        {
            *prx16bits = (uint16_t)tmp;

            prx16bits++;
        }
    }

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return rval;
}



/**
  * @brief    In single-line half-duplex mode, a certain amount of data is
  *         received, and then a certain amount of data is sent.
  * @param  pHUsart  Pointer to a USART_HandleTypeDef structure that contains
  *                the configuration information for the specified USART.
  * @param  pTxData  Pointer to transmit data buff(uint8 or uint16 data elements).
  * @param  TxSize   Amount of data elements (uint8 or uint16) to be sent.
  * @param  pRxData  Pointer to receive data buff(uint8 or uint16 data elements).
  * @param  RxSize   Amount of data elements (uint8 or uint16) to be received.
  * @param  Timeout  Timeout duration.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_HalfDuplex_ReceiveTransmit(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint16_t TxSize, uint8_t *pRxData, uint16_t RxSize, uint32_t Timeout)
{
    HAL_StatusTypeDef   rval      = HAL_OK;
    uint8_t             *ptx8bits   = NULL;
    uint8_t             *prx8bits   = NULL;
    uint16_t            *ptx16bits  = NULL;
    uint16_t            *prx16bits  = NULL;
    uint32_t            tickstart   = 0U;
    uint16_t            tmp         = 0U;

    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }
    if( (!pTxData) ||
        (!pRxData) ||
        (!TxSize) ||
        (!RxSize) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_HALFDUPLEX_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->TxXferCount = TxSize;
    pHUsart->TxXferSize = TxSize;
    pHUsart->RxXferCount = RxSize;
    pHUsart->RxXferSize = RxSize;

    __HAL_USART_CLEAR_FEFLAG(pHUsart);

    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_TE_Msk);
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_RE_Msk);

    if( (pHUsart->Init.Parity == USART_PARITY_NONE) &&
        (pHUsart->Init.WordLength == USART_WORDLENGTH_9B) )
    {
        ptx16bits = (uint16_t *)pTxData;
        prx16bits = (uint16_t *)pRxData;
    }
    else
    {
        ptx8bits = (uint8_t *)pTxData;
        prx8bits = (uint8_t *)pRxData;
    }

    while( pHUsart->RxXferCount )
    {
        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_RXNE, RESET, tickstart, Timeout);
        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }

        if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_PE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_PARITY;
        }
        if( __HAL_USART_GET_FLAG(pHUsart, USART_FLAG_FE) )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_FE;
        }

        tmp = READ_REG(pHUsart->Instance->DR);

        pHUsart->RxXferCount--;

        if( prx8bits )
        {
            *prx8bits = (uint8_t)tmp;

            prx8bits++;
        }
        else
        {
            *prx16bits = (uint16_t)tmp;

            prx16bits++;
        }
    }

    CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_RE_Msk);
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_TE_Msk);

    while( pHUsart->TxXferCount )
    {
        if( ptx8bits )
        {
            WRITE_REG_MASK(pHUsart->Instance->CR1, USART_DR_8BIT, *ptx8bits);

            ptx8bits++;
        }
        else
        {
            WRITE_REG_MASK(pHUsart->Instance->CR2, USART_DR_9BIT, *ptx16bits);

            ptx16bits++;
        }

        pHUsart->TxXferCount--;

        rval = _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_RXNE, RESET, tickstart, Timeout);

        if( rval == HAL_TIMEOUT )
        {
            pHUsart->ErrorCode |= HAL_USART_ERROR_TIMEOUT;

            break;
        }
    }

    _USART_WaitOnFlagUntilTimeout(pHUsart, USART_FLAG_TC, RESET, tickstart, Timeout);

    pHUsart->gState = HAL_USART_STATE_READY;

    __HAL_UNLOCK(pHUsart);

    return rval;
}


//=============================================================================
//                         USART PDMA Function
//=============================================================================
#if defined(HAL_DMA_MODULE_ENABLED)
/**
  * @brief  DMA module is used to control USART to send quantitative data.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pTxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Transmit_DMA(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint16_t Size)
{
    HAL_StatusTypeDef rval = HAL_OK;

    if( pHUsart->gState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }
    if( (!pTxData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_TX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->TxXferCount = Size;
    pHUsart->TxXferSize = Size;

    //Config PDMA ctrl USART transmit parameters.
     __HAL_USART_DISABLE(pHUsart);
    rval = _USART_Transmit_PDMA_Config(pHUsart, pTxData, Size);
    __HAL_USART_ENABLE(pHUsart);
    if( rval != HAL_OK )
    {
        pHUsart->gState = HAL_USART_STATE_READY;

        __HAL_UNLOCK(pHUsart);

        return rval;
    }

    //Clear transmit interrupt flag.
    __HAL_USART_CLEAR_FLAG(pHUsart, USART_FLAG_TC);

    __HAL_UNLOCK(pHUsart);

    //Enable USART DMA start work bit data.
    SET_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);

    return rval;
}



/**
  * @brief  DMA module is used to control USART to receive quantitative data.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pRxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be receive.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Receive_DMA(USART_HandleTypeDef *pHUsart, uint8_t *pRxData, uint16_t Size)
{
    HAL_StatusTypeDef rval = HAL_OK;

    if( pHUsart->RxState != HAL_USART_STATE_READY )
    {
        return HAL_BUSY;
    }
    if( (!pRxData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    __HAL_LOCK(pHUsart);

    pHUsart->RxState = HAL_USART_STATE_BUSY_RX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->RxXferCount = Size;
    pHUsart->RxXferSize = Size;

    //Configure the relevant parameters needed for DMA to ctrl USART receive data.
    __HAL_USART_DISABLE(pHUsart);
    rval = _USART_Receive_PDMA_Config(pHUsart, pRxData, Size);
    __HAL_USART_ENABLE(pHUsart);
    if( rval != HAL_OK )
    {
        pHUsart->RxState = HAL_USART_STATE_READY;

        __HAL_UNLOCK(pHUsart);

        return rval;
    }

    __HAL_USART_CLEAR_PEFLAG(pHUsart);

    __HAL_UNLOCK(pHUsart);

    //Enable USART PE/FE/ORE check nvic interrupt bit data.
    //Enable USART start to use DMA receive data bit data.
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);
    SET_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAR_Msk | USART_CR3_EIE_Msk));

    return rval;
}



/**
  * @brief    The DMA module is used to control the USART to send and receive
  *         quantitative data.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pTxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  pRxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent and receive.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_TransmitReceive_DMA(USART_HandleTypeDef *pHUsart, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
{
    HAL_StatusTypeDef rval = HAL_OK;

    if( (pHUsart->gState != HAL_USART_STATE_READY) ||
        (pHUsart->RxState != HAL_USART_STATE_READY) )
    {
        return HAL_BUSY;
    }
    if( (!pTxData) ||
        (!pRxData) ||
        (!Size) )
    {
        return HAL_ERROR;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));
    assert_param(IS_USART_WORDLENGTH(pHUsart->Init.WordLength));
    assert_param(IS_USART_PARITY(pHUsart->Init.Parity));

    __HAL_LOCK(pHUsart);

    pHUsart->gState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->RxState = HAL_USART_STATE_BUSY_TX_RX;
    pHUsart->ErrorCode = HAL_USART_ERROR_NONE;

    pHUsart->TxXferCount = Size;
    pHUsart->TxXferSize = Size;
    pHUsart->RxXferCount = Size;
    pHUsart->RxXferSize = Size;

    //  Configure the relevant parameters needed for DMA to ctrl USART
    //send and receive data.
    __HAL_USART_DISABLE(pHUsart);
    rval = _USART_Transmit_PDMA_Config(pHUsart, pTxData, Size);
    if( rval != HAL_OK )
    {
        __HAL_USART_ENABLE(pHUsart);

        pHUsart->gState = HAL_USART_STATE_READY;
        pHUsart->RxState = HAL_USART_STATE_READY;

        __HAL_UNLOCK(pHUsart);

        return rval;
    }

    rval = _USART_Receive_PDMA_Config(pHUsart, pRxData, Size);
    __HAL_USART_ENABLE(pHUsart);
    if( rval != HAL_OK )
    {
        pHUsart->gState = HAL_USART_STATE_READY;
        pHUsart->RxState = HAL_USART_STATE_READY;

        __HAL_UNLOCK(pHUsart);

        return rval;
    }

    __HAL_USART_CLEAR_FLAG(pHUsart, USART_FLAG_TC);
    __HAL_USART_CLEAR_PEFLAG(pHUsart);

    __HAL_UNLOCK(pHUsart);

    //Enable USART PE/FE/ORE check nvic interrupt bit data.
    //Enable USART start to use DMA send and receive data bit data.
    SET_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);
    SET_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAT_Msk | USART_CR3_DMAR_Msk | USART_CR3_EIE_Msk));

    return rval;
}



/**
  * @brief  Pauses the DMA Transfer.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_DMAPause(USART_HandleTypeDef *pHUsart)
{
    uint32_t reg3enable = 0U;

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    reg3enable = READ_REG(pHUsart->Instance->CR3);

    if( (pHUsart->gState == HAL_USART_STATE_BUSY_TX) &&
        (reg3enable & USART_CR3_DMAT_Msk) )
    {
        CLEAR_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);
    }

    if( (pHUsart->RxState == HAL_USART_STATE_BUSY_RX) &&
        (reg3enable & USART_CR3_DMAR_Msk) )
    {
        CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);
        CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_EIE_Msk | USART_CR3_DMAR_Msk));
    }

    if( ((pHUsart->gState == HAL_USART_STATE_BUSY_TX_RX) &&
         (pHUsart->RxState == HAL_USART_STATE_BUSY_TX_RX)) &&
        (reg3enable & (USART_CR3_DMAT_Msk | USART_CR3_DMAR_Msk)) )
    {
        CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);
        CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_EIE_Msk | USART_CR3_DMAR_Msk | USART_CR3_DMAT_Msk));
    }

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Resumes the DMA Transfer.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_DMAResume(USART_HandleTypeDef *pHUsart)
{
    uint32_t reg3tmp = 0U;

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    reg3tmp = READ_REG(pHUsart->Instance->CR3);

    if( (pHUsart->gState == HAL_USART_STATE_BUSY_TX) &&
        (!(reg3tmp & USART_CR3_DMAT_Msk)) )
    {
        SET_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);
    }

    if( (pHUsart->RxState == HAL_USART_STATE_BUSY_RX) &&
        (!(reg3tmp & USART_CR3_DMAR_Msk)) )
    {
        __HAL_USART_CLEAR_OREFLAG(pHUsart);

        SET_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);
        SET_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAR_Msk | USART_CR3_EIE_Msk));
    }

    if( ( (pHUsart->gState == HAL_USART_STATE_BUSY_TX_RX) &&
        (pHUsart->RxState == HAL_USART_STATE_BUSY_TX_RX) ) &&
        (!(reg3tmp & (USART_CR3_DMAT_Msk | USART_CR3_DMAR_Msk) ) ) )
    {
        __HAL_USART_CLEAR_OREFLAG(pHUsart);

        SET_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);
        SET_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAT_Msk | USART_CR3_DMAR_Msk | USART_CR3_EIE_Msk));
    }

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Stops the DMA Transfer.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_DMAStop(USART_HandleTypeDef *pHUsart)
{
    uint32_t reg3tmp = 0U;

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    reg3tmp = READ_REG(pHUsart->Instance->CR3);

    if( (pHUsart->gState == HAL_USART_STATE_BUSY_TX) &&
        (reg3tmp & USART_CR3_DMAT_Msk) )
    {
        CLEAR_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);
        CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_TCIE_Msk | USART_CR1_TXEIE_Msk));

        HAL_DMA_Channel_Stop(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_TX));

        pHUsart->gState = HAL_USART_STATE_READY;
    }

    if( (pHUsart->RxState == HAL_USART_STATE_BUSY_RX) &&
        (reg3tmp & USART_CR3_DMAR_Msk) )
    {
        CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);
        CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_EIE_Msk | USART_CR3_DMAR_Msk));

        HAL_DMA_Channel_Stop(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_RX));

        pHUsart->RxState = HAL_USART_STATE_READY;
    }

    if( ((pHUsart->gState == HAL_USART_STATE_BUSY_TX_RX) &&
         (pHUsart->RxState == HAL_USART_STATE_BUSY_TX_RX)) &&
        (reg3tmp & (USART_CR3_DMAT_Msk | USART_CR3_DMAR_Msk)) )
    {
        CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAR_Msk | USART_CR3_DMAT_Msk | USART_CR3_EIE_Msk));
        CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_TCIE_Msk | USART_CR1_TXEIE_Msk | USART_CR1_PEIE_Msk));

        HAL_DMA_Channel_Stop(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_TX));
        HAL_DMA_Channel_Stop(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_RX));

        pHUsart->gState = HAL_USART_STATE_READY;
        pHUsart->RxState = HAL_USART_STATE_READY;
    }

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}




/**
  * @brief  Pauses the DMA Transmit.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Asynchronous_Transmit_DMAPause(USART_HandleTypeDef *pHUsart)
{
    uint32_t  reg3enable = 0U;

    if( (pHUsart->gState != HAL_USART_STATE_BUSY_TX) &&
        (pHUsart->gState != HAL_USART_STATE_BUSY_TX_RX) )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    reg3enable = READ_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);
    if( reg3enable )
    {
        CLEAR_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);
    }

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Resume the DMA Transfer.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Asynchronous_Transmit_DMAResume(USART_HandleTypeDef *pHUsart)
{
    uint32_t  reg3enable = 0U;

    if( (pHUsart->gState != HAL_USART_STATE_BUSY_TX) &&
        (pHUsart->gState != HAL_USART_STATE_BUSY_TX_RX) )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    reg3enable = READ_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);
    if( !reg3enable )
    {
        SET_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);
    }

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Stop the DMA Transfer.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Asynchronous_Transmit_DMAStop(USART_HandleTypeDef *pHUsart)
{
    uint32_t  reg3enable = 0U;

    if( (pHUsart->gState != HAL_USART_STATE_BUSY_TX) &&
        (pHUsart->gState != HAL_USART_STATE_BUSY_TX_RX) )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    reg3enable = READ_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);
    if( reg3enable )
    {
        CLEAR_BIT(pHUsart->Instance->CR3, USART_CR3_DMAT_Msk);
        CLEAR_BIT(pHUsart->Instance->CR1, (USART_CR1_TCIE_Msk | USART_CR1_TXEIE_Msk));

        HAL_DMA_Channel_Stop(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_TX));

        pHUsart->gState = HAL_USART_STATE_READY;
    }

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Pause the DMA Receive.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Asynchronous_Receive_DMAPause(USART_HandleTypeDef *pHUsart)
{
    uint32_t reg3enable = 0U;

    if( (pHUsart->RxState != HAL_USART_STATE_BUSY_RX) &&
        (pHUsart->RxState != HAL_USART_STATE_BUSY_TX_RX) )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    reg3enable = READ_BIT(pHUsart->Instance->CR3, USART_CR3_DMAR_Msk);
    if( reg3enable )
    {
        CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAR_Msk | USART_CR3_EIE_Msk));
        CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);
    }

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Resume the DMA Receive.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Asynchronous_Receive_DMAResume(USART_HandleTypeDef *pHUsart)
{
    uint32_t reg3enable = 0U;

    if( (pHUsart->RxState != HAL_USART_STATE_BUSY_RX) &&
        (pHUsart->RxState != HAL_USART_STATE_BUSY_TX_RX) )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    reg3enable = READ_BIT(pHUsart->Instance->CR3, USART_CR3_DMAR_Msk);
    if( !reg3enable )
    {
        __HAL_USART_CLEAR_OREFLAG(pHUsart);

        SET_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);
        SET_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAR_Msk | USART_CR3_EIE_Msk));
    }

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



/**
  * @brief  Stop the DMA Receive.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_Asynchronous_Receive_DMAStop(USART_HandleTypeDef *pHUsart)
{
    uint32_t reg3enable = 0U;

    if( (pHUsart->RxState != HAL_USART_STATE_BUSY_RX) &&
        (pHUsart->RxState != HAL_USART_STATE_BUSY_TX_RX) )
    {
        return HAL_BUSY;
    }

    assert_param(IS_USART_INSTANCE(pHUsart->Instance));

    __HAL_LOCK(pHUsart);

    reg3enable = READ_BIT(pHUsart->Instance->CR3, USART_CR3_DMAR_Msk);
    if( reg3enable )
    {
        CLEAR_BIT(pHUsart->Instance->CR3, (USART_CR3_DMAR_Msk | USART_CR3_EIE_Msk));
        CLEAR_BIT(pHUsart->Instance->CR1, USART_CR1_PEIE_Msk);

        HAL_DMA_Channel_Stop(pHUsart->pHDma, _USART_GetPDMAChannel(pHUsart, HAL_USART_STATE_BUSY_RX));

        pHUsart->RxState = HAL_USART_STATE_READY;
    }

    __HAL_UNLOCK(pHUsart);

    return HAL_OK;
}



#endif      //__HAL_DMA_MODULE_ENABLED

#endif      //__HAL_USART_ENABLE__

